﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using agvcontroller.Common;
using agvcontroller.Log;

namespace agvcontroller.Driver
{
    delegate void deleRcvMsg(object sender, string msg);
    delegate void deleSocketReportConnect(object sender, enumConnect connect);
    delegate void deleSocketReportCommunication(object sender, enumCommnication communication);
    delegate void deleSocketReportControl(object sender, enumContolState control);
    delegate void deleSocketReportOperation(object sender, enumOperation operation);
    delegate void deleSocketReportAlarm(object sender, int alarmid, bool set);
    delegate void deleSocketReportPosition(object sender, int prenode, int curnode, int nextnode);
    delegate void deleSocketAcceptVehicleJob(object sender, int vehiclejobid);
    delegate void deleSocketRejectVehicleJob(object sender, int vehiclejobid);
    delegate void deleSocketCompletedVehicleJob(object sender, int vehiclejobid);
    delegate void deleSocketReportInterlockSignal(object sender, List<int> interlock);

    class CVehicleSocketDriver 
    {
        public event deleRcvMsg onReceiveMessage;
        public event deleSocketReportConnect onConnect;

        Thread threadServer;
        Socket Server;
        Socket Client;
        IPAddress ClientIP;
        IPAddress ServerIP;
        int Port;

        Logger Log;

        public bool Connected
        {
            get;
            set;
        }

        public CVehicleSocketDriver(IPAddress serverip, IPAddress clientip, int port)
        {
            ServerIP = serverip;
            ClientIP = clientip;
            Port = port;

            Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            threadServer = new Thread(new ThreadStart(ServerProc));

            Log = new Logger(string.Format("VehicleSocketDriver({0})", port));

            Log.Info(string.Format("Create SocketDriver({0})", Port));
        }

        ~CVehicleSocketDriver()
        {
            Close();
        }

        public int StartListen()
        {
            try
            {
                IPEndPoint serverEndPoint = new IPEndPoint(ClientIP == null ? IPAddress.Any : ClientIP, Port==0?10000:Port);
                Server.Bind(serverEndPoint);
                Server.Listen(1);
                Server.Blocking = true;     // The server socket is working in blocking mode

                threadServer.Start();

                Log.Info(string.Format("SocketDriver Start Listen({0})",Port));

            }
            catch (SocketException ex)
            {
                Log.Info(string.Format("Exception SocketDriver Start Listen({0}) ,{1}",Port, ex.Message));

                return CReturnCode.ERR_SOCKET_OPEN_FAILURE;
            }

            return CReturnCode.SUCCESS;
        }

        public int Close()
        {
            Server.Close();
            
            if (Client != null)
            {
                Client.Disconnect(true);
                Client.Close();
            }

            threadServer.Abort();

            Connected = false;

            if (onConnect != null)
                onConnect(this,enumConnect.DISCONNECTION);

            Log.Info(string.Format("SocketDriver Closed({0})",Port));

            return CReturnCode.SUCCESS;
        }

        public void ServerProc()
        {
            while (true)
            {
                byte[] buffer = new byte[1024];
                string msg;

                if (Connected == false)
                {
                    if (onConnect != null)
                        onConnect(this, enumConnect.DISCONNECTION);

                    Client = Server.Accept();
                    Connected = true;

                    if(onConnect!=null)
                        onConnect(this, enumConnect.CONNECTION);
                }
                else
                {
                    try
                    {
                        int length = Client.Receive(buffer);
                        if (length == 0)       // If the client is disconnected
                        {
                            Close();
                        }
                        else                // If data from client is arrived
                        {
                            msg = System.Text.Encoding.ASCII.GetString(buffer);

                            ReceiveMessage(msg);
                            //(new EventHandler(ReceiveMessage));


                        }
                    }
                    catch (SocketException ex)
                    {
                        Close();
                        Log.Info(string.Format("Exception Server Process({0}) : {1} , ", Port, ex.Message));
                    }
                    Thread.Sleep(100);
                }
            }
        }

        void ReceiveMessage(string msg)
        {
            if (onReceiveMessage != null)
                onReceiveMessage(this, msg);

            Log.Info(string.Format("Received Message ({0}) : {1}",Port, msg));

        }

        public void Send(string msg)
        {
            try
            {
                Byte[] sendBytes = Encoding.ASCII.GetBytes(msg);
                Client.Send(sendBytes, 0, sendBytes.Length, SocketFlags.None);

                Log.Info(string.Format("Send Message ({0}) : {1}",Port, msg));

            }
            catch (Exception ex)
            {
                Close();

                Log.Info(string.Format("Exception Send Message ({0}) : {1} , {2} ",Port, msg, ex.Message));
            }
        }
    }
}
